import { _decorator, Color, Component, Graphics, Label, Mask, Node, Tween, tween, UITransform, v3 } from 'cc';
import { AudioManager } from '../../../frame/component/audio-manager';
import GameDC from '../../data/data.game.center';
const { ccclass, property } = _decorator;

/** 引导的完成类型（指示引导是如何被完成的） */
enum DoneType {
	/** 点击完成 */
	TOUCH,
	/** 延时完成 */
	DELAY,
	/**  */
	DONE,
}

@ccclass('Guide')
export class Guide extends Component {
	@property(Mask)
	private mask: Mask = null;
	@property(UITransform)
	private toucher: UITransform;
	@property(UITransform)
	private pointer: UITransform = null;
	@property(UITransform)
	private content: UITransform = null;
	@property(Label)
	private lbl_content: Label = null;

	private uitrans: UITransform;
	private ui_mask: UITransform;
	private mask_graphics: Graphics;

	public static DoneType = DoneType;

    protected start() {
		if([1, 2, 3].every(id=>GameDC.checkGuideID(id))){
			this.node.removeFromParent();
			this.node.destroy();
		}else{
			Guide.ins = this;
			this.init();
			if(Guide.show_step!=undefined) this.show(Guide.show_step.step);
		}

		GameDC.Status.guide_inited = true;
    }

	private init(){
		this.uitrans = this.node.getComponent(UITransform);
		this.ui_mask = this.mask.getComponent(UITransform);
		this.mask_graphics = this.mask.node.getComponent(Graphics);
		this.toucher.node.on(Node.EventType.TOUCH_END, this.touchEnd);

		this.node.active = false;
	}

	private showContent(content: string, target: UITransform){
		this.content.node.active = true;
		this.lbl_content.string = content;

		let position = target ? this.uitrans.convertToNodeSpaceAR(target.node.worldPosition) : v3(0, 0, 0);
		let va = new mtec.cc.VecAssist(this.content.node);

		if(position.x<0) position.x = Math.max(position.x, va.left);
		else if(position.x > 0) position.x = Math.min(position.x, va.right);

		if(target){
			if(position.y<0) position.y += (1-target.anchorY) * target.height + this.content.height * 0.5 + 50;
			else position.y -= target.anchorY * target.height + this.content.height * 0.5 + 50;
		}

		Tween.stopAllByTarget(this.content.node);
		tween(this.content.node)
		.to(0.25, {position: v3(position.x, position.y, this.content.node.position.z)})
		.start();
	}

	private light_local = v3(0, 0, 0);
	/**
	 * 显示高亮区域
	 * @param list
	 */
	private showLight(...list: UITransform[]){
		this.mask_graphics.clear();
		this.mask_graphics.fillColor = Color.BLACK;

		if(list.length>0){
			list.forEach(ui=>{
				this.ui_mask.convertToNodeSpaceAR(ui.node.worldPosition, this.light_local);
				this.mask_graphics.fillRect(
					this.light_local.x - ui.anchorX * ui.width,
					this.light_local.y - ui.anchorY * ui.height,
					ui.width, ui.height
				);
			});
		}
		//this.graphics.clear();
		//this.graphics.fillColor = this.clean_color;
		//this.graphics.rect(
		//	-0.5 * this.ui_graphics.width,
		//	-0.5 * this.ui_graphics.height,
		//	this.ui_graphics.width,
		//	this.ui_graphics.height
		//);
		//this.graphics.fill();

		//if(list.length<=0){
		//	return void 0;
		//}

		//this.graphics.fillColor = this.light_color;
		//list.forEach(ui=>{
		//	this.ui_graphics.convertToNodeSpaceAR(ui.node.worldPosition, this.light_local);
		//	this.graphics.rect(
		//		this.light_local.x - ui.anchorX * ui.width,
		//		this.light_local.y - ui.anchorY * ui.height,
		//		ui.width, ui.height
		//	);
		//	this.graphics.fill();
		//});
	}

	/**
	 * 显示引导动画(小手的动画)
	 * @param target
	 */
	private showPointer(target: UITransform){
		let position = this.uitrans.convertToNodeSpaceAR(target.node.worldPosition);

		position.x += (0.5-target.anchorX) * target.width;
		position.y += (0.5-target.anchorY) * target.height;

		Tween.stopAllByTarget(this.pointer.node);
		this.pointer.node.active = true;
		this.pointer.node.setPosition(position.x, position.y, this.pointer.node.position.z);

		let ratio = 1 / 3;
		let distance1 = v3(this.pointer.width * ratio, this.pointer.height * -ratio, 0);
		let distance2 = v3(this.pointer.width * -ratio, this.pointer.height * ratio, 0);
		tween(this.pointer.node)
		.by(0.15, {position: distance1})
		.by(0.15, {position: distance2})
		.union().repeat(3).delay(0.8)
		.union().repeatForever().start();
	}

	private refreshToucher(target: UITransform){
		let position = this.uitrans.convertToNodeSpaceAR(target.node.worldPosition);

		position.x += (0.5-target.anchorX) * target.width;
		position.y += (0.5-target.anchorY) * target.height;

		this.toucher.node.setPosition(position.x, position.y, this.toucher.node.position.z);
		this.toucher.setContentSize(target.contentSize);
	}

	private async show(step: GuideStep, delay?: number){

		this.node.active = true;
		this.mask_graphics.clear();
		this.ui_mask.node.active = false;
		this.content.node.active = false;
		this.pointer.node.active = false;

		await mtec.delay(delay ?? 1, 'end');

		if(step.content){
			this.content.node.active = true;
			this.showContent(step.content, step.light_target??step.pointer_target);
		}

		if(step.pointer_target){
			this.pointer.node.active = true;
			this.showPointer(step.pointer_target);
		}

		let ui_list = [step.light_target, step.pointer_target].filter(ui=>Boolean(ui));
		this.ui_mask.node.active = true;
		if(ui_list.length>0){
			this.showLight(...ui_list);
		}

		if(step.pointer_target){
			this.refreshToucher(step.pointer_target);
		}

		step.npromise_show.resolve(true);
	}

	private close(){
		Tween.stopAllByTarget(this.pointer.node);
		this.node.active = false;
	}

	private touchEnd(){
		Guide.Done(Guide.show_step.id, DoneType.TOUCH);
	}

	/** 引导步骤记录 */
	private static step_map = new Map<number, GuideStep>();
	/** 当前正在显示的引导数据 */
	private static show_step: {id: number, step: GuideStep};
	private static ins: Guide;
	private static wait_close = new Map<number, boolean>();

	/**
	 * 创建一个引导步骤
	 * @param id
	 */
	public static Create(id: number, content?: string, light_target?: UITransform, pointer_target?: UITransform){
		let step = Guide.step_map.get(id);
		if(!step){
			step = {
				npromise_show: new mtec.NudityPromise(),
				npromise_done: new mtec.NudityPromise(),
			};
			Guide.step_map.set(id, step);
			Guide.wait_close.set(id, true);
		};

		Object.assign(step, {content, light_target, pointer_target});
		if(GameDC.checkGuideID(id)){
			step.inited = true;
			step.npromise_show.resolve(true);
			Guide.Done(id, DoneType.DONE);
		}

		if(!step.inited) step.inited = ![content, light_target, pointer_target].map(v=>v==undefined).every(v=>v==true);
		return step;
	}

	/**
	 * 显示一个引导步骤
	 * @param id 引导步骤的id
	 */
	public static Show(id: number, delay?: number, timeout?: number){
		if(Guide.show_step != undefined){
			console.error('当前有正在显示中的引导，显示逻辑冲突' + Guide.show_step);
			return void 0;
		}
		if(!Guide.step_map.has(id)) throw TypeError('Create a guide step with id: '+id+' before showing it!!!');

		let step = Guide.step_map.get(id);
		if(step.done) return step.npromise_show.promise;
		if(step.inited){
			Guide.show_step = {id, step};
			if(Guide.ins){
				Guide.ins.show(step, delay)
				.then(()=>{
					if(!step.pointer_target && !(timeout>0)){
						timeout = 2;
					}
					if(timeout){
						mtec.delay(timeout, ()=>Guide.Done(id, DoneType.DELAY));
					}
				})
			}
			return step.npromise_show.promise;
		}else{
			console.error('未初始化的引导步骤，请在引导步骤显示之前，进行初始化配置', step);
		}
	}

	/**
	 * 完成一个引导步骤
	 * @param id 引导步骤的id
	 */
	public static Done(id: number, type: DoneType){
		if(!Guide.step_map.has(id)) throw ReferenceError('No guide step with id: '+id+' is found. Please confirm whether it was created!!!');
		let step = Guide.step_map.get(id);
		step.done = true;

		if(Guide.show_step && Guide.show_step.id==id){
			Guide.show_step = undefined;
			let close = Guide.wait_close.get(id);
			if(close && Guide.ins) Guide.ins.close();
		}

		if(!GameDC.checkGuideID(id)) GameDC.DoneGuideID(id);

		if(type==DoneType.TOUCH) AudioManager.playEffect(AudioManager.EAudio.EF_CLICK);
		step.npromise_done.resolve(type);
	}

	/**
	 * 等待一个引导步骤id
	 * @param id 引导步骤的id
	 */
	public static Wait(id: number, close = true){
		let step = Guide.step_map.get(id);
		if(!step) step = Guide.Create(id);
		Guide.wait_close.set(id, close);
		return step.npromise_done.promise;
	}

	/**
	 * 判断是否存在指定id的引导步骤
	 * @param id 引导步骤的id
	 */
	public static Has(id: number){
		return Guide.step_map.has(id);
	}

	/**
	 * 判断是否存在指定id的引导步骤
	 * @param id 引导步骤的id
	 */
	public static Get(id: number){
		return Guide.step_map.get(id);
	}

	/**
	 * 清除指定id的引导步骤
	 * @param list
	 */
	public static CleanGuideStep(...list: number[]){
		list.forEach(id=>{
			if(Guide.step_map.has(id)) Guide.step_map.delete(id);
			if(Guide.show_step && Guide.show_step.id==id) Guide.show_step = undefined;
		});
	}
}

/** 引导步骤数据结构 */
interface GuideStep {
	/** 可供操作的promise */
	npromise_show: mtec.NudityPromise<boolean>;
	npromise_done: mtec.NudityPromise<DoneType>;
	/** 引导文案 */
	content?: string;
	/** 高亮区域 */
	light_target?: UITransform;
	/** 指引区域（也就是小手的动画） */
	pointer_target?: UITransform;
	/** 引导数据是否初始化 */
	inited?: boolean;
	done?: boolean;
	/** 引导是如何被完成的 */
	done_type?: DoneType;
};
